\chapter{模块设计}
\section{IF模块}
指令缓存和终端处理在拓展部分详细说明，本部分完成了取指的简单功能。

\begin{figure}
\centering
\includegraphics[width=0.8\textwidth]{if.png}
\caption{IF模块}
\end{figure}

\begin{enumerate}
\item 锁存器: 保证 PC 只在整个时钟周期的一半中工作
\item ADD: PC+1
\item 选通: 由Hazard Detector控制，选出实际使用的指令。
\item 中断处理: 接受PC+1，PC，实际指令，判断中断情况。将适当值传入段间寄存器。并由Hazard Detector控制
\end{enumerate}

\section{ID模块}

\begin{figure}
\centering
\includegraphics[width=0.8\textwidth]{id.png}
\caption{ID模块}
\end{figure}

\begin{enumerate}
\item OP/IM: 将输入的指令转化为Opcode，同时进行立即数拓展处理。\\
输入: 原指令\\
输出: 给控制器CON的控制信号; Opcode; 处理后的立即数\\
\item CON: 各个阶段都存在的部件，生成本阶段的控制信号\\
输入: Opcode\\
输出: 寄存器选址器的控制信号\\
\item ADD: 将PC与立即数相加\\
输入: PC，IMM\\
输出: PC+IMM\\
\item A: ALU第一个操作数的选通器\\
输入: MEM段数据旁路，ALU计算结果的数据旁路，PC，寄存器堆输出1\\
输出: 选通值\\
\item B: ALU第二个操作数的选通器\\
输入: IMM，寄存器堆输出2\\
输出: 选通值\\
\item 寄存器堆\\
输入: 读地址1，读地址2，写入地址，写入值，写入开关\\
输出: 输出1，输出2\\
其中写入地址，写入值，写入开关是由WB阶段生成的。\\
\item PC选择器: 在本阶段选择合适的PC回传给IF阶段\\
输入: PC，ADD输出，A输出\\
输出: PC\\
\item Hazard Detector\\
输入: 寄存器选址器所得的1和2地址\\
输出: A，B以及PC选择器的控制信号\\
\end{enumerate}

此部分完成生成Opcode并后传，取得寄存器值，计算PC等一系列工作。处理数据冲突的结果反映在这一阶段，以下详细描述。\\

引起数据冲突的原因在于ID阶段需要使用后面阶段所产生的值，但这些值并没有及时写回寄存器，导致ID阶段取到的值不正确，因此我们加入数据旁路，当所需的值被产生之后立即将其引回所需的地方（一般来说是一个选通器），我们通过Hazard Detector来判断这种情况是否发生，如果发生，则使用Hazard Detector让对应的选通器选择旁路引导过去的值。具体来说有这么几种情况：

\begin{enumerate}
\item 引起冲突的两个阶段目前在ID和EXE阶段，并且EXE阶段指令没有MEM操作。此时ALU的输出被旁路回引，选通器A选出正确的值供下一阶段使用。
\item 引起冲突的两个阶段目前在ID和EXE阶段，并且EXE阶段指令有MEM操作。此时Hazard Detector会暂停整个流水线1阶段将流水线拖入3情况
\item 引起冲突的两个阶段目前在ID和MEM阶段，并且MEM阶段指令有MEM操作。由于我们执行内存读写操作时，流水线会暂停知道其结束，所以不需要针对数据冲突的操作。
\end{enumerate}

这样我们就解决了数据冲突的问题。

附件：

立即数扩展方式

\begin{flushleft}
\begin{tabular}{|c|c|c|c|c|c|c|c|}
\hline
\multicolumn{5}{|c|}{pattern} & \multicolumn{3}{c|}{method}\tabularnewline
\hline
10\_8 & 7\_5 & 4\_2 & 1\_0 & position & unsigned & signed & shift\tabularnewline
\hline
 & \multicolumn{3}{c|}{imm} & last 8 bits & EX\_U8 & EX\_S8 & EX\_NONE\tabularnewline
\hline
\multicolumn{2}{|c|}{} & \multicolumn{2}{c|}{0 imm} & last 4 bits & EX\_INT & EX\_S4 & EX\_NONE\tabularnewline
\hline
\multicolumn{4}{|c|}{imm} & last 11 bits & EX\_NONE & EX\_S11 & EX\_NONE\tabularnewline
\hline
\multicolumn{2}{|c|}{} & \multicolumn{2}{c|}{imm} & last 5 bits & EX\_NONE & EX\_S5 & EX\_NONE\tabularnewline
\hline
\multicolumn{2}{|c|}{} & imm &  & 4 downto 2 & EX\_NONE & EX\_NONE & EX\_SHIFT\tabularnewline
\hline
\end{tabular}
\par\end{flushleft}

\section{EXE模块}
\begin{figure}
\centering
\includegraphics[width=0.6\textwidth]{exe.png}
\caption{EXE模块}
\end{figure}

\begin{enumerate}
\item JUDGE0: 这个部件用于判断输入中的某个数是否是零或者不是，也接受外界输入来锁定输出\\
输入: ALU计算结果，控制器控制信号CON\\
输出: 将CON与ALU计算结果异或，如果CON为某个值会锁定输出为0\\
\item ALUOP: 用于将opcode进一步转换为ALU自己的操作编码\\
输入: Opcode\\
输出: ALUOpcode\\
\item 选通器\\
输入: PC，IMM，寄存器堆输出2\\
输出: MEM部分所使用的内存地址写入值\\
\item CON: EXE阶段控制器\\
输入: Opcode\\
输出: 各部件控制信号\\
\item ALU\\
输入: 输入1, 输入2, ALUOpcode\\
输出: 计算结果\\
\item Hazard Detector\\
输入: Opcode，寄存器写入地址，Judge0输出\\
输出: 无\\
\end{enumerate}

本阶段完成主要运算工作。是花费时间最多的部分，我们根据设计的通路，设计了详细的表格，其中包括每条指令对各个部件的信号。

% DataPath.XLS

\begin{figure}
\begin{tabular}{ll}
    ALUOP\_ADD   & 0x0000 \\
    ALUOP\_SUB   & 0x0001 \\
    ALUOP\_AND   & 0x0010 \\
    ALUOP\_OR    & 0x0011 \\
    ALUOP\_XOR   & 0x0100 \\
    ALUOP\_LESSU & 0x0101 \\
    ALUOP\_LESS  & 0x0110 \\
    ALUOP\_SLL   & 0x0111 \\
    ALUOP\_SRA   & 0x1000 \\
    ALUOP\_SRL   & 0x1001 \\
    ALUOP\_NOT   & 0x1010 \\
    ALUOP\_NEG   & 0x1011 \\
    ALUOP\_REG1  & 0x1100 \\
    ALUOP\_REG2  & 0x1101 \\
    ALUOP\_SUB2  & 0x1110
\end{tabular}
\end{figure}


\section{MEM模块}
\begin{figure}
\centering
\includegraphics[width=0.8\textwidth]{mem.png}
\caption{MEM模块}
\end{figure}

\begin{enumerate}
\item Memory
输入: ALU计算结果并向后传递，MEM写入值，MEM写控制\\
输出: 内存堆输出\\
其中MEM写控制由EXE部分的con来生成。
\item Hazard Detector: 根据Opcode以及寄存器写回地址判定流水线是否需要暂停\\
输入: Opcode, 寄存器写回地址\\
输出: 无\\
\end{enumerate}

此部分实现对内存堆的读写。通过段间寄存器向后一级传递Opcode，寄存器写回地址，内存对输出，ALU计算结果即可。

\section{WB模块}
\begin{figure}
\centering
\includegraphics[width=0.8\textwidth]{wb.png}
\caption{WB模块}
\end{figure}

\begin{enumerate}
\item 选通器: 选择某个值送回ID阶段的寄存器堆\\
输入: ALU输出, 内存对输出\\
输出: 选通结果\\
\item CON: 生成本部分各部件控制信号\\
输入: Opcode\\
输出: 寄存器堆读写开关，选通器控制信号\\
\end{enumerate}

本部分完成写回功能，从两个来源中选择一个作为最后写入寄存器堆的值，同时将传入的寄存器堆地址，寄存器写入开关传回。

\section{冲突处理}

本部件为工程中最复杂的部件。设计之初没有考虑做一个这样的东西是因为没有正面考虑处理冲突，后来发现如果要比较漂亮的解决冲突，而又不给编程造成太大压力，把实现集中到一个部件中比较好（但设计复杂度会增加）。\\

本部件还有一些连线和段间寄存器连在一起，用于暂停整个流水线。具体来说，当Hazard Detector发现有必要暂停流水线的时候，他向四个段间寄存器发出信号。所有的段间寄存器储存所有送入的值，直到Hazard Detector发出下一个信号。然而有的时候我们只希望PC停止工作，而不希望后面的部分停止工作，所以我们在第一个段间寄存器中放置了一个信号发生器，当某个条件发生时，向PC发出相应信号让他停止。\\

